package org.Yiran.timetale_re.worldgen.feature;

import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import org.Yiran.timetale_re.block.BlocksRegister;
import org.Yiran.timetale_re.block.crystal.EnergyCrystalClusterBlock;
import org.Yiran.timetale_re.worldgen.feature.config.CrystalClusterConfig;

import java.util.ArrayList;
import java.util.List;

/**
 * 能晶簇特征类
 * <p>
 * 这个类实现了在世界中生成能晶簇的逻辑。
 * 能晶簇会在岩浆池旁边生成，附着在合适的方块上。
 */
public class EnergyCrystalClusterFeature extends Feature<CrystalClusterConfig> {
    
    public EnergyCrystalClusterFeature(Codec<CrystalClusterConfig> codec) {
        super(codec);
    }

    @Override
    public boolean place(FeaturePlaceContext<CrystalClusterConfig> context) {
        WorldGenLevel level = context.level();
        BlockPos origin = context.origin();
        RandomSource random = context.random();
        CrystalClusterConfig config = context.config();
        
        // 检查生成位置是否合适
        if (!level.isEmptyBlock(origin)) {
            return false;
        }
        
        // 检查附近是否有岩浆（缩小检查范围）
        if (!isNearLava(level, origin)) {
            return false;
        }
        
        // 生成能晶簇
        return generateEnergyCrystalCluster(level, origin, config, random);
    }
    
    /**
     * 检查位置附近是否有岩浆
     * 
     * @param level 世界
     * @param pos 位置
     * @return 如果附近有岩浆返回true，否则返回false
     */
    private boolean isNearLava(WorldGenLevel level, BlockPos pos) {
        // 缩小检查范围到5x5x5（原来为9x9x9），提高匹配概率
        for (int dx = -2; dx <= 2; dx++) {
            for (int dy = -2; dy <= 2; dy++) {
                for (int dz = -2; dz <= 2; dz++) {
                    BlockPos checkPos = pos.offset(dx, dy, dz);
                    BlockState state = level.getBlockState(checkPos);
                    if (state.is(Blocks.LAVA)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    
    /**
     * 生成能晶簇
     * 
     * @param level 世界
     * @param origin 原点位置
     * @param config 配置
     * @param random 随机数生成器
     * @return 是否生成成功
     */
    private boolean generateEnergyCrystalCluster(WorldGenLevel level, BlockPos origin, 
                                               CrystalClusterConfig config, RandomSource random) {
        // 确定能晶簇的大小 (1-4个)
        int clusterSize = config.minClusterSize() + random.nextInt(config.maxClusterSize() - config.minClusterSize() + 1);
        
        // 生成能晶簇位置
        List<BlockPos> positions = getEnergyClusterPositions(level, origin, clusterSize, random);
        if (positions.isEmpty()) {
            return false;
        }
        
        // 生成能晶
        boolean success = false;
        for (BlockPos pos : positions) {
            if (level.isEmptyBlock(pos)) {
                // 为每个能晶独立选择附着面，增加多样性
                Direction validAttachDirection = getAttachDirection(level, pos, random);
                if (validAttachDirection != null) {
                    // 能晶等级（根据配置的最高等级随机）
                    int crystalLevel = config.minCrystalLevel() + 
                                     random.nextInt(config.maxCrystalLevel() - config.minCrystalLevel() + 1);
                    
                    if (placeEnergyCrystal(level, pos, validAttachDirection, crystalLevel)) {
                        success = true;
                    }
                }
            }
        }
        
        return success;
    }
    
    /**
     * 获取合适的附着面
     * 
     * @param level 世界
     * @param pos 位置
     * @param random 随机数生成器
     * @return 附着面，如果找不到合适的附着面则返回null
     */
    private Direction getAttachDirection(WorldGenLevel level, BlockPos pos, RandomSource random) {
        // 检查六个方向是否有合适的附着面
        List<Direction> validDirections = new ArrayList<>();
        for (Direction direction : Direction.values()) {
            BlockPos attachPos = pos.relative(direction.getOpposite());
            BlockState attachState = level.getBlockState(attachPos);
            
            // 检查是否是石头、深层板岩、末地石或岩浆块
            if (isStoneTypeBlock(attachState, level)) {
                validDirections.add(direction);
            }
        }
        
        // 如果有有效的附着面，随机选择一个
        if (!validDirections.isEmpty()) {
            return validDirections.get(random.nextInt(validDirections.size()));
        }
        
        return null;
    }
    
    /**
     * 检查方块是否为石头类型（可用于附着能晶簇）
     * 
     * @param state 方块状态
     * @param level 世界
     * @return 如果是石头类型返回true，否则返回false
     */
    private boolean isStoneTypeBlock(BlockState state, WorldGenLevel level) {
        // 检查是否在下界
        boolean isInNether = level.getLevel().dimension() == net.minecraft.world.level.Level.NETHER;
        
        if (isInNether) {
            // 在下界中，能晶簇可以附着在下界岩上
            return state.is(BlockTags.BASE_STONE_NETHER) || 
                   state.is(Blocks.NETHERRACK) ||
                   state.is(Blocks.MAGMA_BLOCK);
        } else {
            // 在主世界中，能晶簇可以附着在石头类方块上
            return state.is(BlockTags.STONE_ORE_REPLACEABLES) || 
                   state.is(BlockTags.DEEPSLATE_ORE_REPLACEABLES) ||
                   // 末地石和岩浆块没有专门的BlockTags，需要直接检查
                   state.is(Blocks.END_STONE) ||
                   state.is(Blocks.MAGMA_BLOCK);
        }
    }
    
    /**
     * 获取能晶簇的位置
     * 
     * @param level 世界
     * @param origin 原点
     * @param count 能晶数量
     * @param random 随机数生成器
     * @return 位置列表
     */
    private List<BlockPos> getEnergyClusterPositions(WorldGenLevel level, BlockPos origin, int count, RandomSource random) {
        List<BlockPos> positions = new ArrayList<>();
        positions.add(origin);
        
        // 从原点开始向外扩散生成位置
        BlockPos current = origin;
        for (int i = 1; i < count; i++) {
            // 在当前点的附近寻找空位
            BlockPos next = findNearbyValidPosition(level, current, positions, random);
            if (next != null) {
                positions.add(next);
                current = next;
            } else {
                // 如果找不到合适的位置，尝试从已有的位置中选择一个继续扩散
                if (!positions.isEmpty()) {
                    current = positions.get(random.nextInt(positions.size()));
                    next = findNearbyValidPosition(level, current, positions, random);
                    if (next != null) {
                        positions.add(next);
                        current = next;
                    }
                }
            }
        }
        
        return positions;
    }
    
    /**
     * 寻找附近的空位
     * 
     * @param level 世界
     * @param center 中心点
     * @param occupied 已占用位置
     * @param random 随机数生成器
     * @return 附近的空位，如果找不到则返回null
     */
    private BlockPos findNearbyValidPosition(WorldGenLevel level, BlockPos center, List<BlockPos> occupied, RandomSource random) {
        // 在中心点周围寻找
        for (int attempts = 0; attempts < 15; attempts++) {
            int dx = random.nextInt(3) - 1; // -1, 0, 1
            int dy = random.nextInt(3) - 1;
            int dz = random.nextInt(3) - 1;
            
            BlockPos pos = center.offset(dx, dy, dz);
            
            // 检查位置是否已被占用
            if (occupied.contains(pos)) {
                continue;
            }
            
            // 检查位置是否为空并且附近有合适的附着面
            if (level.isEmptyBlock(pos) && hasValidAttachSurface(level, pos)) {
                return pos;
            }
        }
        
        return null;
    }
    
    /**
     * 检查位置附近是否有有效的附着面
     * 
     * @param level 世界
     * @param pos 位置
     * @return 如果有有效的附着面返回true，否则返回false
     */
    private boolean hasValidAttachSurface(WorldGenLevel level, BlockPos pos) {
        // 检查六个方向是否有合适的附着面
        for (Direction direction : Direction.values()) {
            BlockPos attachPos = pos.relative(direction.getOpposite());
            BlockState attachState = level.getBlockState(attachPos);
            
            // 检查是否是石头、深层板岩、末地石或岩浆块
            if (isStoneTypeBlock(attachState, level)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 放置单个能晶
     * 
     * @param level 世界
     * @param pos 位置
     * @param attachDirection 附着方向
     * @param levelValue 能晶等级
     * @return 是否放置成功
     */
    private boolean placeEnergyCrystal(WorldGenLevel level, BlockPos pos, Direction attachDirection, int levelValue) {
        try {
            // 设置方块状态
            BlockState state = ((EnergyCrystalClusterBlock) BlocksRegister.ENERGY_CRYSTAL_CLUSTER.get()).defaultBlockState()
                    .setValue(EnergyCrystalClusterBlock.FACING, attachDirection)
                    .setValue(EnergyCrystalClusterBlock.LEVEL, levelValue);
            
            // 放置方块
            level.setBlock(pos, state, 2);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}